﻿using SharpDX;
using SharpDX.Direct3D11;
using System.Runtime.InteropServices;

namespace Engine.Graphics.Shaders.C11UndercoverShaders
{
    internal class ShaderBaseC11Undercover : ShaderBase, ISetShaderValues
    {
        private string name;
        private SharpDX.Direct3D11.Buffer textureMatrixBuffer;

        private BufferDescription uvCoordinateBufferDescription;

        private TextureMatrixC11Undercover textureMatrix = new TextureMatrixC11Undercover();

        [StructLayout(LayoutKind.Explicit, Size = 96)]
        internal struct TextureMatrixC11Undercover
        {
            [FieldOffset(0)]
            public Vector3 textureMatrix1a;

            [FieldOffset(16)]
            public Vector3 textureMatrix1b;

            [FieldOffset(32)]
            public Vector3 textureMatrix2a;

            [FieldOffset(48)]
            public Vector3 textureMatrix2b;

            [FieldOffset(64)]
            public Vector4 textureMod1;

            [FieldOffset(80)]
            public Vector4 textureMod2;
        }

        public ShaderBaseC11Undercover(Device renderDevice)
            : base(renderDevice)
        {
            // Buffer for uvTexture Matrices
            this.uvCoordinateBufferDescription = new BufferDescription()
            {
                BindFlags = BindFlags.ConstantBuffer,
                CpuAccessFlags = CpuAccessFlags.None,
                OptionFlags = ResourceOptionFlags.None,
                SizeInBytes = Marshal.SizeOf(typeof(TextureMatrixC11Undercover)),
                Usage = ResourceUsage.Default
            };

            this.textureMatrixBuffer = SharpDX.Direct3D11.Buffer.Create(renderDevice, ref textureMatrix, uvCoordinateBufferDescription);
            this.textureMatrixBuffer.DebugName = "Cobra11 texture Matrix Buffer";
        }

        public ShaderBase Effect
        {
            get { return this; }
        }

        public void SetTextureUvMatrix(Material material)
        {
#if DEBUG
            ShaderBase.lastHashcodeMappingMatrix1 = 0;
            ShaderBase.lastHashcodeMappingMatrix2 = 0;
            ShaderBase.lastHashcodeMappingMatrix3 = 0;
#endif

            if (ShaderBase.lastHashcodeMappingMatrix1 != material.Mappings1.CRC ||
                ShaderBase.lastHashcodeMappingMatrix2 != material.Mappings2.CRC ||
                ShaderBase.lastHashcodeMappingMatrix3 != material.Mappings3.CRC)
            {
                //this.textureMatrix.textureMod1 = material.GetMappings1A();
                //this.textureMatrix.textureMod2 = material.GetMappings1B();
                this.textureMatrix.textureMod1 = material.GetMappings1A();
                this.textureMatrix.textureMod2 = material.GetMappings1B();

                //this.textureMatrix.textureMod1 = new Vector4(0, 0, 0.5f, 0.5f);
                //this.textureMatrix.textureMod2 = new Vector4(0, 0, 0.05f, 0.05f);
                //this.textureMatrix.textureMod1 = new Vector4(0, 0, 3.0f, 0.0f);
                //this.textureMatrix.textureMod1.Z = 3; // Wie groß die Textur angezeigt wird.

                // this.textureMatrix.textureMod2 = new Vector4(0, 0, 0.0f, 0.0f);

                this.textureMatrix.textureMatrix1a = new Vector3(new float[] { 1.0f, 0.0f, 0.0f });
                this.textureMatrix.textureMatrix1b = new Vector3(new float[] { 0.0f, 1.0f, 0.0f });
                this.textureMatrix.textureMatrix2a = new Vector3(new float[] { 1.0f, 0.0f, 0.0f });
                this.textureMatrix.textureMatrix2b = new Vector3(new float[] { 0.0f, 1.0f, 0.0f });

                lock (this.device.ImmediateContext)
                {
                    this.device.ImmediateContext.UpdateSubresource(ref this.textureMatrix, this.textureMatrixBuffer);
                    this.device.ImmediateContext.VertexShader.SetConstantBuffer(1, this.textureMatrixBuffer);
                }
                ShaderBase.lastHashcodeMappingMatrix1 = material.Mappings1.CRC;
                ShaderBase.lastHashcodeMappingMatrix2 = material.Mappings2.CRC;
                ShaderBase.lastHashcodeMappingMatrix3 = material.Mappings3.CRC;
            }
        }

        public string Name
        {
            get
            {
                return this.name;
            }
            set
            {
                this.name = value;
            }
        }

        public new void Dispose()
        {
            base.Dispose();
            this.textureMatrixBuffer.Dispose();
        }

        public void SetProperties(int materialID, MaterialManager materialManager)
        {
            Material material = materialManager.GetMaterial(materialID);
            SetTexture(0, material.GetTexture1(materialManager));
            SetTexture(1, material.GetBumpTexture1(materialManager));
            SetTexture(2, material.GetTexture2(materialManager));
            SetTexture(3, material.GetBumpTexture2(materialManager));
            SetTexture(4, material.GetTexture3(materialManager));
            SetTexture(5, material.GetBumpTexture3(materialManager));

            SetTextureUvMatrix(material);
        }
    }
}